package com.gci.lib_markdown_editor.editor

import android.app.AlertDialog
import android.content.Context
import android.graphics.Color
import android.os.Environment
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.*
import com.gci.lib_markdown_editor.R
import com.gci.lib_markdown_editor.viewer.MarkdownView
import com.jhonjson.dialoglib.BottomListDialog
import java.io.File

class NoteEditor @JvmOverloads constructor(
        context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), View.OnClickListener, MarkdownView.MarkdownListener {
    override fun onUrlClicked(url: String?) {
        listener.onUrlClicked(url!!)
    }

    override fun onPageLoadFinished() {
        progressBarContainer.visibility = View.GONE
    }


    private var isNormal = true
    private var cacheText: String? = null
    private var cache: ArrayList<String> = ArrayList()

    //views
    private var editText: EditText
    private var markdownView: MarkdownView
    private var btnHeader: ImageButton
    private var btnList: ImageButton
    private var btnQuote: ImageButton
    private var btnImage: ImageButton
    private var btnText: ImageButton
    private var btnCode: ImageButton
    private var btnUrl: ImageButton
    private var btnLine: ImageButton
    private var btnTop: ImageButton
    private var btnBottom: ImageButton
    private var btnUndo: ImageButton
    private var btnRedo: ImageButton
    private var progressBarContainer: RelativeLayout

    private var bottomLayout: ScrollView

    //font size
    var fs: Float = 12.toFloat()
        set(value) {
            field = value
            editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, field)
        }

    //attributes
    private var isEditorView = true

    val NOTE_DIR = Environment.getExternalStorageDirectory().path + "/" + context.packageName + "/markdown"
    lateinit var listener: OnClickListener
    var outputFile: File? = null

    enum class MODE {
        EDITOR_MODE,
        VIEWER_MODE
    }


    interface OnClickListener {
        fun onAddImageClick(curPosition: Int)
        fun onUrlClicked(url: String)
    }

    init {
        val editorView = LayoutInflater.from(context)
                .inflate(R.layout.layout_editor, null)

        editText = editorView.findViewById(R.id.editText)
        markdownView = editorView.findViewById(R.id.markdownView)
        btnHeader = editorView.findViewById(R.id.btnHeader)
        btnList = editorView.findViewById(R.id.btnList)
        btnQuote = editorView.findViewById(R.id.btnQuote)
        btnImage = editorView.findViewById(R.id.btnImage)
        btnText = editorView.findViewById(R.id.btnText)
        btnCode = editorView.findViewById(R.id.btnCode)
        btnUrl = editorView.findViewById(R.id.btnUrl)
        btnLine = editorView.findViewById(R.id.btnLine)
        btnTop = editorView.findViewById(R.id.btnTop)
        btnBottom = editorView.findViewById(R.id.btnBottom)
        btnUndo = editorView.findViewById(R.id.btnUndo)
        btnRedo = editorView.findViewById(R.id.btnRedo)
        bottomLayout = editorView.findViewById(R.id.bottomLayout)
        progressBarContainer = editorView.findViewById(R.id.progrebar_container)
        progressBarContainer.visibility = View.GONE

        markdownView.visibility = View.GONE
        markdownView.setOnMarkdownListener(this@NoteEditor)

        /**
        markdownView.setOnMarkdownClickedListener(object :MarkdownViewClickListener{
        override fun onUrlClicked(url: String?) {
        listener.onUrlClicked(url!!)
        }

        override fun onPageLoadFinished() {
        progressBarContainer.visibility = View.GONE
        }
        })
         */

        btnHeader.setOnClickListener(this@NoteEditor)
        btnList.setOnClickListener(this@NoteEditor)
        btnQuote.setOnClickListener(this@NoteEditor)
        btnImage.setOnClickListener(this@NoteEditor)
        btnText.setOnClickListener(this@NoteEditor)
        btnCode.setOnClickListener(this@NoteEditor)
        btnUrl.setOnClickListener(this@NoteEditor)
        btnLine.setOnClickListener(this@NoteEditor)
        btnTop.setOnClickListener(this@NoteEditor)
        btnBottom.setOnClickListener(this@NoteEditor)
        btnUndo.setOnClickListener(this@NoteEditor)
        btnRedo.setOnClickListener(this@NoteEditor)

        editText.setOnKeyListener { _, keyCode, _ ->
            if (keyCode == KeyEvent.KEYCODE_ENTER) {
                saveMarkdownFile(outputFile!!)
                cache.add(editText.text.toString())
            }
            false

        }



        editText.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                outputFile?.let { saveMarkdownFile(outputFile!!) }
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

            }

        })

        markdownView.isOpenUrlInBrowser = true

        addView(editorView)

    }


    fun saveMarkdownFile(file: File) {
        if (!file.exists())
            file.createNewFile()
        file.writeText(editText.text.toString())
    }

    fun saveTempChange(file: File?) {
        file?.writeText(editText.text.toString())
    }

    override fun onClick(v: View?) {
        saveTempChange(outputFile)
        setEditorMode(MODE.EDITOR_MODE)
        val lines = editText.text.toString().split("\n")
        var lastLine = lines[lines.lastIndex]
        if (lastLine.isNotEmpty()) {
            editText.append("\n\n")
            editText.setSelection(editText.text.length)
        }

        when (v!!.id) {
            btnHeader.id -> {
                editText.requestFocus()
                val curPosition = editText.selectionStart
                val headers = resources.getStringArray(R.array.headers)
                BottomListDialog.Builder(context)
                        .addMenuListItem(headers) { position: Int ->
                            when (position) {
                                0 -> {
                                    editText.append("# ")
                                    editText.setSelection(curPosition + 2)
                                }
                                1 -> {
                                    editText.append("## ")
                                    editText.setSelection(curPosition + 3)
                                }
                                2 -> {
                                    editText.append("### ")
                                    editText.setSelection(curPosition + 4)
                                }
                            }
                            editText.showKeyBoard()
                        }
                        .show()
            }

            btnList.id -> {

                if (lines.size > 1 && lastLine.isEmpty()) {

                    lastLine = lines[lines.lastIndex - 1]
                }
                var lastOrderIndex = 0
                if (lastLine.matches("^\\d+\\. .*".toRegex())) {
                    lastOrderIndex = lastLine.substringBefore(".").toInt()
                } else {
                    lastOrderIndex = 0
                }
                val curPosition = editText.selectionStart
                val listStyle = resources.getStringArray(R.array.list)
                BottomListDialog.Builder(context)
                        .addMenuListItem(listStyle) { pos: Int ->
                            when (pos) {
                                0 -> {
                                    val promote = "${lastOrderIndex + 1}. "
                                    editText.append("${lastOrderIndex + 1}. ")
                                    editText.setSelection(curPosition + promote.length)
                                }
                                1 -> {
                                    editText.append("+ ")
                                    editText.setSelection(curPosition + 2)
                                }
                            }
                            editText.showKeyBoard()
                        }
                        .show()
            }

            btnText.id -> {
                val curPosition = editText.selectionStart
                val titls = resources.getStringArray(R.array.text)
                BottomListDialog.Builder(context)
                        .addMenuListItem(titls) { pos: Int ->
                            when (pos) {
                                0 -> {
                                    editText.append("****")
                                    editText.setSelection(curPosition + 2)
                                }
                                1 -> {
                                    editText.append("**")
                                    editText.setSelection(curPosition + 1)
                                }
                                2 -> {
                                    editText.append("******")
                                    editText.setSelection(curPosition + 3)
                                }
                                3 -> {
                                    editText.append("~~~~")
                                    editText.setSelection(curPosition + 2)

                                }
                                4 -> {
                                    editText.append("<sup></sup>")
                                    editText.setSelection(curPosition + 5)
                                }
                                5 -> {
                                    editText.append("<sub></sub>")
                                    editText.setSelection(curPosition + 5)
                                }
                            }
                            editText.showKeyBoard()

                        }
                        .show()
            }

            btnQuote.id -> {
                val curPosition = editText.selectionStart
                editText.append(">")
                editText.setSelection(curPosition + 1)
                editText.showKeyBoard()
            }

            btnCode.id -> {
                val curPosition = editText.selectionStart
                editText.append("```\n\n\n```")
                editText.setSelection(curPosition + 4)
                editText.showKeyBoard()
            }

            btnImage.id -> {
                val curPosition = editText.selectionStart
                listener.onAddImageClick(curPosition)
            }

            btnUrl.id -> {
                val dialogView = LayoutInflater.from(context)
                        .inflate(R.layout.layout_add_url, null)
                val etDialogTitle = dialogView.findViewById<EditText>(R.id.et_title)
                val etDialogAddress = dialogView.findViewById<EditText>(R.id.et_address)
                AlertDialog.Builder(context)
                        .setTitle(R.string.add_url)
                        .setView(dialogView)
                        .setPositiveButton(R.string.OK) { _, _ ->
                            val title = etDialogTitle.text.toString()
                            val address = etDialogAddress.text.toString()
                            if (title.isNotBlank() && address.isNotBlank()) {
                                addUrl(title, address)
                            }
                        }
                        .setNeutralButton(R.string.cancel, null)
                        .show()
            }

            btnLine.id -> {
                val curPosition = editText.selectionStart
                editText.append("----\n\n")
                editText.setSelection(curPosition + 6)
            }

            btnTop.id -> {
                editText.setSelection(0)
            }

            btnBottom.id -> {
                editText.setSelection(editText.text.length)
            }

            btnUndo.id -> {
                cacheText = editText.text.toString()
                if (cache.size > 0) {
                    editText.setText(cache[cache.lastIndex])
                    cache.removeAt(cache.lastIndex)
                    editText.setSelection(cache[cache.lastIndex].length)
                }

            }

            btnRedo.id -> {
                if (cacheText != null) {
                    editText.setText(cacheText)
                    editText.setSelection(cacheText!!.length)
                }
            }


        }

        markdownView.visibility = View.GONE
    }

    fun refresh() {
        markdownView.setMarkDownText(editText.text.toString())
    }

    fun addUrl(title: String = "", url: String = "") {
        isEditorView = true
        editText.setSelection(getInsertPosition())
        val syntax = "\n[$title]($url)\n"
        addMarkdown(syntax)
        saveMarkdownFile(outputFile!!)
        editText.requestFocus()
    }

    fun addVideoPoster(title: String, source: String, src: String) {
        isEditorView = true
        val syntax = "\np{$title}[$source]($src)\n"
        addMarkdown(syntax)
        saveMarkdownFile(outputFile!!)
        editText.requestFocus()
    }

    fun addVideo(title: String, source: String) {
        isEditorView = true
        val syntax = "\nv{$title}[$source]\n"
        addMarkdown(syntax)
        saveMarkdownFile(outputFile!!)
        editText.requestFocus()
    }

    fun addAudio(title: String, source: String) {
        isEditorView = true
        val syntax = "\ni{$title}[$source]\n"
        addMarkdown(syntax)
        saveMarkdownFile(outputFile!!)
        editText.requestFocus()
    }

    fun addImageUrl(title: String, url: String, imagePath: String) {
        isEditorView = true
        val syntax = "\ni{$title}[$imagePath]($url)\n"
        //val syntax = "\n<a href=\"$url\"><img src=\"$imagePath\">$title</img></a>\n"
        addMarkdown(syntax)
        //editText.setSelection(getInsertPosition())
        //editText.append("\n<a href=\"$url\"><img src=\"$imagePath\">$title</img></a>\n")
        saveMarkdownFile(outputFile!!)
        editText.requestFocus()
    }

    fun addClickableImage(imagePath: String, title: String="") {
        addImageUrl(title, imagePath, imagePath)
    }

    fun addMarkdown(syntax: String) {
        val pos = getInsertPosition()
        val text = editText.text.toString()
        var prefix = text.substring(0,pos)
        if (!isInEmptyLine()){
            prefix = "$prefix\n"
        }
        editText.setText(prefix + syntax + text.substring(pos, text.length))
        editText.setSelection(pos + syntax.length)
    }

    fun isInEmptyLine(): Boolean {
        val selection = editText.selectionStart
        val text = editText.text.toString()
        val curLine = text.substring(0, selection).substringAfterLast("/n") + text.substringBeforeLast("/n")
        if (curLine.isBlank()){
            return true
        }
        return false
    }

    fun setTheme() {
        isNormal = !isNormal
        setNight(isNormal)
    }

    fun setNight(isNormal: Boolean) {
        if (!isNormal) {
            editText.setTextColor(Color.WHITE)
            editText.setBackgroundColor(context.getColor(R.color.colorBottomBgColor))
        } else {
            editText.setTextColor(context.getColor(R.color.colorBottomBgColor))
            editText.setBackgroundColor(Color.WHITE)
        }
    }

    fun EditText.showKeyBoard() {
        this.postDelayed(Runnable {
            this.requestFocus()
            val inputManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            inputManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
        }, 200)
    }

    fun addColorText(text: String, isBool: Boolean, isItalic: Boolean, color: String, textSize: String) {
        val sb = StringBuilder()
        sb.append("\nc{title}")
        if (isBool) {
            sb.append("b")
        }
        if (isItalic) {
            sb.append("i")
        }

        if (color.isNotBlank()) {
            sb.append("#$color")
        }

        if (textSize.isNotBlank()) {
            sb.append("${textSize}pt")
        }
        sb.append("\n")

        val syntax = sb.toString()
        addMarkdown(syntax)
        saveMarkdownFile(outputFile!!)
        requestFocus()


    }

    fun addVideoMark(title: String, imagePath: String, filePath: String, position: Int) {
        val syntax = "\ni{$title}[$imagePath]($filePath#$position)"
        addMarkdown(syntax)
        saveMarkdownFile(outputFile!!)

    }

    fun addImage(imagePath: String, position: Int = -1) {
        Log.i("NoteEditor", imagePath)
        val name = getFileName(imagePath)
        val syntax = "\n![$name]($imagePath)\n\n"
        addMarkdown(syntax)
        //editText.append("\n![$name]($imagePath)\n\n")
        saveMarkdownFile(outputFile!!)
    }

    fun getFileName(filePath: String): String {
        return filePath.substringAfterLast("/").substringBeforeLast(".")
    }

    fun setEditorMode(mode: MODE) {
        when (mode) {
            MODE.EDITOR_MODE -> {
                progressBarContainer.visibility = View.GONE
                editText.isEnabled = true
                markdownView.visibility = View.GONE
                bottomLayout.visibility = View.VISIBLE
            }
            MODE.VIEWER_MODE -> {
                progressBarContainer.visibility = View.VISIBLE
                editText.isEnabled = false
                markdownView.visibility = View.VISIBLE
                markdownView.setMarkDownText(editText.text.toString())
                bottomLayout.visibility = View.GONE
            }
        }
    }

    fun setText(content: String) {
        editText.setText(content)
        editText.setSelection(editText.text.length)
    }

    fun setFocus() {
        editText.requestFocus()
        editText.setSelection(editText.text.length)
    }

    fun isEmpty(): Boolean {
        return editText.text.isBlank()
    }

    fun save() {
        saveMarkdownFile(outputFile!!)
    }

    fun getInsertPosition(): Int {
        val curPosition = editText.selectionStart
        val text = editText.text.toString()
        if (text.isEmpty()) {
            return 0
        } else {
            val aText = text.substring(curPosition, text.length)
            return curPosition + aText.substringBefore('\n').length
        }
    }

    fun onlyTitle(s: String): Boolean {
        val text = editText.text.toString().replace("\n", "").replace(" ", "")
        val title = s.replace("\n", "").replace(" ", "")
        return text == title
    }
}


